use libloading::Symbol;

use common_base::{
    prelude::*,
    serde::{self, Deserialize},
};

use crate::{
    service_engine::service_model::ServiceContextBuilderCreator, support::DylibRepository,
    ServiceContextBuilder,
};

#[derive(Deserialize, Debug)]
#[serde(crate = "self::serde")]
#[serde(rename_all = "camelCase")]
pub struct ServiceContextBuilderStub {
    comp_creator: String,
    #[serde(rename = "iD")]
    id: String,
}

impl ServiceContextBuilderStub {
    pub fn load_service_context_builder(
        &self,
        dylib_repository: &DylibRepository,
    ) -> Result<Box<dyn ServiceContextBuilder>> {
        let dylib_and_func = self.comp_creator.split("::").collect::<Vec<&str>>();
        if dylib_and_func.len() != 2 || dylib_and_func[0].is_empty() || dylib_and_func[1].is_empty()
        {
            return Err(ErrorCode::DylibLoadFailed(format!(
                "ServiceContextBuilderStub[{}] comp_creator format error, should be `dylib_name::creator_func_name`, but is {}.",
                self.id,
                self.comp_creator
            )));
        }
        unsafe {
            let _guard = dylib_repository.get_or_create(dylib_and_func[0])?;
            let func: Symbol<ServiceContextBuilderCreator> =
                _guard.value().get(dylib_and_func[1].as_bytes())?;
            let context_builder = *Box::from_raw(func());
            info!("load {} successed", dylib_and_func[1]);
            Ok(context_builder)
        }
    }
}
